package drazing;

import java.awt.Dimension;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;

/**
 * Controla todos los datos y variables de carrera
 * @author xcubo
 */
public final class ControladorCarrera
{
        //Variables iniciales
        private int ALTO, ANCHO;
        private int numCoches;
        private int laps;

        private int sect;

        private Cronometro crono;
        private int best_lap;

        //Componentes de ControladorCarrera
        private Pista circuit;
        private Car Parrilla[];
        private boolean offRoad;

        private Settings setup;
        

        private PhysicsEngine   phys;

        private long lastTime;
        private long thisTime;


        /**
         * Genera un ControladorCarrera
         * @param track Circuito a cargar
         * @param num Cantidad de coches
         * @param ancho Ancho de pantalla
         * @param alto Alto de pantalla
         * @param conf Settings del jugador
         */
        public ControladorCarrera(int track, int num, int ancho, int alto, Settings conf)
        {
                //Parámetros
                circuit = new Pista(track);
                numCoches=num;
                ANCHO = ancho;
                ALTO = alto;
                setup = conf;

                //Genera los coches y el panel
                Parrilla=new Car[numCoches];
                laps = 0;
                crono = new Cronometro();
                
                best_lap = 0;
                sect = 1;

                

                cargarMyCar();
                phys = new PhysicsEngine(this);
                lastTime = 0;
        }

        /**
         * Crea el coche del jugador
         */
        void cargarMyCar()
        {
            Parrilla[0] = new Car(1338,568,setup);
        }

        /**
         * Pasa una vuelta
         * @param c Coche que la da
         */
        public void newLap (Car c)
        {
            boolean valid=true;
            Tiempo aux1 = new Tiempo(0,0,0,0);
            if (sect != 3)
                valid = false;
            if (valid)
            {
                double secs = crono.getTime();
                aux1.setSeconds(secs);
            }
            c.setTime(laps, new Tiempo(aux1.getHours(),aux1.getMinutes(),aux1.getSeconds(),aux1.getCents()));

            Tiempo best = setup.getTime();

            if ((laps == 1 || best.isZero()) && valid)
            {
                best = c.getTime(laps);
                best_lap = laps;
            }
            else if (c.getTime(laps).toSeconds() < best.toSeconds() && valid)
            {
                best = c.getTime(laps);
                best_lap = laps;
            }
            setup.setTime(best);
            laps++;
            if (crono.isRunning())
                crono.reset();
            else
                crono.go();
            sect = 1;
        }
        
        /**
         * Devuelve el coche del jugador
         * @return myCar
         */
        public Car getMyCar()
        {
            return Parrilla[0];
        }
        public Car getCar(int i)
        {
            return Parrilla[i];
        }

        public Pista getCircuit()
        {
            return circuit;
        }

        public int getNumCoches()
        {
            return this.numCoches;
        }
        public int getLaps()
        {
            return laps;
        }
        public String getBestTime()
        {
            return setup.getTime().toString();
        }
        public void updateSector(Point2D pto)
        {
            double x = pto.getX();
            double y = pto.getY();
            Rectangle2D meta = circuit.getEndLine();

            if (x < 1500 && y > 1400 && sect == 1)
                sect = 2;
            else if (x < 920 && y < 1400 && sect == 2)
                sect = 3;
            else if (x > meta.getX() && y > meta.getY() && sect == 3)
                newLap(Parrilla[0]);
        }
        public int getSector()
        {
            return sect;
        }
        public Cronometro getCrono()
        {
            return crono;
        }
        public int getBestLap()
        {
            return best_lap;
        }
        public boolean isOffRoad()
        {
            return offRoad;
        }
        public void isOffRoad(boolean x)
        {
            offRoad = x;
        }
        public Dimension getDimension()
        {
            return new Dimension(ANCHO,ALTO);
        }
        /**
         * Actualiza el estado de la carrera
         */
        public void processes(boolean[] keys)
        {
            Car myCar = Parrilla[0];
            boolean accel=keys[0], brake=keys[1], turnr=keys[2], turnl=keys[3];
            double elapsedTime = 0;

            if (lastTime != 0)
            {
                thisTime = System.currentTimeMillis();
                elapsedTime = (thisTime - lastTime)+1;
                elapsedTime = elapsedTime/1000.0;
            }

            // Vemos si hay colisiones
            phys.collision(myCar);

            // Vemos si estamos fuera del asfalto
            boolean wheel[] = new boolean[4];
            wheel = phys.offRoad(myCar);
            double accel_factor = 1, brake_factor = 1;
            if (wheel[0] || wheel[1] || wheel[2] || wheel[3])
            {
                isOffRoad(true);
                if (wheel[0] || wheel[1])           // Penalizacion de ruedas delanteras
                    brake_factor = 0.08;
                if (wheel[2] || wheel[3])           // Penalizacion de ruedas traseras
                    accel_factor = 0.6;
                myCar.frenar(0.01*elapsedTime);
                myCar.desgastar(elapsedTime*0.5);
            }
            else
                isOffRoad(false);

            // Precalculo la direccion de marcha atrás
            int marchatras = myCar.getOrientacion();
            if (marchatras > 0)
                marchatras -= 32;
            else
                marchatras += 32;

            // Modifico las propiedades del coche según la entrada
            if (accel)
            {
                myCar.acelerar(accel_factor*elapsedTime*25);
                myCar.vaciar(elapsedTime*7);
                myCar.desgastar(elapsedTime*0.1);
            }
            else if (brake && myCar.getSpeed() > 0)
            {
                myCar.frenar(brake_factor*elapsedTime*0.5);
                myCar.desgastar(elapsedTime);
            }
            else if (brake && myCar.getSpeed() <= 0)
                phys.moveCar(myCar, marchatras, 0.5, elapsedTime);
            else if (!accel)
                myCar.decelerar(elapsedTime);
            if (turnl)
            {
                myCar.turn_left(elapsedTime);
                myCar.desgastar(elapsedTime);
            }
            else if (turnr)
            {
                myCar.turn_right(elapsedTime);
                myCar.desgastar(elapsedTime);
            }

            // Muevo el coche
            phys.moveCar(myCar, myCar.getOrientacion(), myCar.getSpeed(), elapsedTime);
            myCar.vaciar(elapsedTime);

            // Actualizo el sector en el que estoy
            updateSector(new Point2D.Double(myCar.getX(),myCar.getY()));

            // Recojo la hora de terminar
            lastTime = System.currentTimeMillis();
        }

}